
const http = require('http');
const WebSocket = require('ws');
const url = require('url');

// 创建HTTP服务器
const server = http.createServer((req, res) => {
    // 设置CORS头，允许跨域请求
    res.setHeader('Access-Control-Allow-Origin', '*');
    res.setHeader('Access-Control-Allow-Methods', 'GET, POST, OPTIONS');
    res.setHeader('Access-Control-Allow-Headers', 'Content-Type');

    // 处理OPTIONS请求
    if (req.method === 'OPTIONS') {
        res.statusCode = 200;
        res.end();
        return;
    }

    res.statusCode = 200;
    res.setHeader('Content-Type', 'text/plain');
    res.end('WebSocket服务器正在运行\n');
});

// 创建WebSocket服务器
const wss = new WebSocket.Server({
    server,
    // 关闭压缩以提高兼容性
    perMessageDeflate: false
});

// 保存连接的客户端
const clients = new Map();
// 保存房间的客户端
const roomClients = new Map();

// 计算活跃连接数
function getActiveConnections() {
    let count = 0;
    clients.forEach((client) => {
        if (client.readyState === WebSocket.OPEN) {
            count++;
        }
    });
    return count;
}

// 处理WebSocket连接
wss.on('connection', (ws, req) => {
    const ip = req.socket.remoteAddress;
    // 解析URL获取roomId
    const parsedUrl = url.parse(req.url, true);
    let roomId = parsedUrl.query.roomId;

    // 如果没有查询参数，尝试从路径中获取roomId
    if (!roomId && req.url.startsWith('/')) {
        roomId = req.url.substring(1); // 移除开头的斜杠
        console.log('从路径中获取roomId:', roomId);
    }

    if (!roomId) {
        console.warn('连接缺少roomId参数，关闭连接');
        ws.close();
        return;
    }

    // 为客户端生成唯一ID
    const clientId = Date.now().toString();
    clients.set(clientId, ws);

    // 将客户端添加到房间
    if (!roomClients.has(roomId)) {
        console.log(`创建新房间: ${roomId}`);
        roomClients.set(roomId, new Set());
    }
    roomClients.get(roomId).add(ws);

    // 记录客户端信息
    ws.roomId = roomId;
    ws.clientId = clientId;

    // 处理消息
    ws.on('message', (message) => {
        try {
            // 确保消息可以被发送
            if (message instanceof Buffer || typeof message === 'string') {
                // 只广播给同一房间的其他客户端
                const roomSet = roomClients.get(roomId);
                if (roomSet) {
                    let broadcastCount = 0;
                    roomSet.forEach((client) => {
                        if (client !== ws && client.readyState === WebSocket.OPEN) {
                            client.send(message);
                            broadcastCount++;
                        }
                    });
                    console.log(`消息已广播给房间 ${roomId} 的 ${broadcastCount} 个客户端`);
                }
            } else {
                console.warn(`收到不支持的消息类型: ${typeof message}`);
            }
        } catch (error) {
            console.error('处理消息时出错:', error);
        }
    });

    // 处理连接关闭
    ws.on('close', (code, reason) => {
        console.log(`客户端断开连接 [${ip}], 代码: ${code}, 原因: ${reason || '无'}`);
        clients.delete(clientId);

        // 从房间中移除客户端
        if (roomId && roomClients.has(roomId)) {
            const roomSet = roomClients.get(roomId);
            roomSet.delete(ws);

            // 如果房间空了，删除房间
            if (roomSet.size === 0) {
                roomClients.delete(roomId);
                console.log(`房间 ${roomId} 已关闭`);
            } else {
                console.log(`房间 ${roomId} 剩余人数: ${roomSet.size}`);
            }
        }

        console.log(`剩余连接数: ${getActiveConnections()}`);
    });

    // 处理错误
    ws.on('error', (error) => {
        console.error(`WebSocket错误 [${ip}]:`, error);
        clients.delete(clientId);

        // 确保在发生错误时也清理连接
        if (roomId && roomClients.has(roomId)) {
            roomClients.get(roomId).delete(ws);
        }
    });

    // 发送欢迎消息
    ws.send(
        JSON.stringify({
            type: 'welcome',
            time: new Date().toISOString(),
            message: `欢迎连接到房间 ${roomId}`,
            roomId: roomId,
            clientId: clientId
        })
    );
});

// 启动服务器
const PORT = process.env.PORT || 9876;
server.listen(PORT, () => {
    console.log(`WebSocket服务器启动成功! 监听端口: ${PORT}`);
    console.log(`日期时间: ${new Date().toLocaleString()}`);
});
